﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace System
{
    /// <summary>
    /// 针对<see langword="Type"/>进行扩展
    /// </summary>
    /// <creator>marc</creator>
    public static class TypeExtensions
    {
        /// <summary>
        /// 生成某类型的默认值
        /// </summary>
        /// <param name="type">指定一个类型</param>
        /// <returns>返回该类型的默认值</returns>
        public static object GetDefaultValue(this Type type)
        {
            if (type.IsValueType)
            {
                return Activator.CreateInstance(type);
            }
            else if (type == typeof(string))
            {
                return string.Empty;
            }
            // 处理数组类型的默认值
            else if (type.IsArray)
            {
                Type elementType = type.GetElementType();
                var arrayInstance = Array.CreateInstance(elementType, 1);
                var elementValue = GetDefaultValue(elementType);
                arrayInstance.SetValue(elementValue, 0);
                return arrayInstance;
            }
            // 处理泛型集合类型的默认值
            else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
            {
                Type elementType = type.GetGenericArguments()[0];
                return new List<object> { GetDefaultValue(elementType) };
            }
            // 处理引用类型的默认值
            else if (type.IsClass)
            {
                var instance = Activator.CreateInstance(type);

                // 递归处理字段
                var fields = type.GetFields();
                foreach (var field in fields)
                {
                    var fieldValue = GetDefaultValue(field.FieldType);
                    field.SetValue(instance, fieldValue);
                }

                // 递归处理属性
                var properties = type.GetProperties();
                foreach (var property in properties)
                {
                    var propertyValue = GetDefaultValue(property.PropertyType);
                    property.SetValue(instance, propertyValue);
                }

                return instance;
            }
            else
            {
                // 处理其他类型的默认值
                return null;
            }
        }

        /// <summary>
        /// 创建某类型的默认值，内部是按值类型和引用类型来处理的
        /// </summary>
        /// <param name="type">指定一个类型</param>
        /// <returns>返回该类型的默认值</returns>
        public static object CreateDefaultValue(this Type type)
        {
            if (type.IsValueType)
            {
                return Activator.CreateInstance(type);
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 检查类型是否可以分配给指定的类型
        /// </summary>
        public static bool IsAssignableTo(this Type type, Type targetType)
        {
            return targetType.IsAssignableFrom(type);
        }

        /// <summary>
        /// 检查类型是否可以分配给指定的类型
        /// </summary>
        public static bool IsAssignableTo<TTarget>(this Type type)
        {
            return type.IsAssignableTo(typeof(TTarget));
        }

        /// <summary>
        /// 获取包含程序集名称的完整类型名称
        /// </summary>
        public static string GetFullNameWithAssemblyName(this Type type)
        {
            return $"{type.FullName}, {type.Assembly.GetName().Name}";
        }

        /// <summary>
        /// 检查类型是否是泛型类型
        /// </summary>
        public static bool IsGenericType(this Type type)
        {
            return type.IsGenericType;
        }

        /// <summary>
        /// 获取类型的泛型类型参数
        /// </summary>
        public static Type[] GetGenericTypeArguments(this Type type)
        {
            return type.IsGenericType ? type.GetGenericArguments() : new Type[0];
        }

        /// <summary>
        /// 检查类型是否是字典类型
        /// </summary>
        public static bool IsDictionary(this Type type)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
        }

        /// <summary>
        /// 检查类型是否是枚举类型
        /// </summary>
        public static bool IsEnum(this Type type)
        {
            return type.IsEnum;
        }

        /// <summary>
        /// 检查类型是否可空（Nullable）类型
        /// </summary>
        public static bool IsNullable(this Type type)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
        }

        /// <summary>
        /// 检查类型是否实现了指定的接口
        /// </summary>
        public static bool ImplementsInterface(this Type type, Type interfaceType)
        {
            return interfaceType.IsAssignableFrom(type) && type.GetInterfaces().Contains(interfaceType);
        }

        /// <summary>
        /// 检查类型是否是可枚举类型
        /// </summary>
        public static bool IsEnumerable(this Type type)
        {
            return type.IsGenericType && typeof(System.Collections.IEnumerable).IsAssignableFrom(type);
        }

        /// <summary>
        /// 检查类型是否是集合类型（数组、列表、字典等）
        /// </summary>
        public static bool IsCollection(this Type type)
        {
            return type.IsArray || (type.IsGenericType && typeof(System.Collections.IEnumerable).IsAssignableFrom(type));
        }

        /// <summary>
        /// 获取类型的友好名称
        /// </summary>
        public static string GetFriendlyName(this Type type)
        {
            if (type.IsGenericType)
            {
                var genericArguments = type.GetGenericArguments();
                var typeName = type.Name.Split('`')[0];
                var genericTypeNames = string.Join(", ", genericArguments.Select(t => t.GetFriendlyName()));
                return $"{typeName}<{genericTypeNames}>";
            }
            else
            {
                return type.Name;
            }
        }

        /// <summary>
        /// 获取类型的所有基类
        /// </summary>
        /// <param name="type"></param>
        /// <param name="includeObject">是否包括 System.Object</param>
        /// <returns></returns>
        public static Type[] GetBaseClasses(this Type type, bool includeObject = true)
        {
            List<Type> list = new List<Type>();
            AddTypeAndBaseTypesRecursively(list, type.BaseType, includeObject);
            return list.ToArray();
        }

        /// <summary>
        /// 获取类型的所有基类
        /// </summary>
        /// <param name="type"></param>
        /// <param name="stoppingType">停止探测基类的类型。此类型将包含在返回的数组中</param>
        /// <param name="includeObject">是否包括 System.Object</param>
        /// <returns></returns>
        public static Type[] GetBaseClasses(this Type type, Type stoppingType, bool includeObject = true)
        {
            List<Type> list = new List<Type>();
            AddTypeAndBaseTypesRecursively(list, type.BaseType, includeObject, stoppingType);
            return list.ToArray();
        }

        private static void AddTypeAndBaseTypesRecursively(List<Type> types, Type type, bool includeObject, Type stoppingType = null)
        {
            if (!(type == null) && !(type == stoppingType) && (includeObject || !(type == typeof(object))))
            {
                AddTypeAndBaseTypesRecursively(types, type.BaseType, includeObject, stoppingType);
                types.Add(type);
            }
        }

        /// <summary>
        /// 获取类型的所有基类（不包括 System.Object）
        /// </summary>
        public static IEnumerable<Type> GetBaseClasses(this Type type)
        {
            var baseType = type.BaseType;
            while (baseType != null && baseType != typeof(object))
            {
                yield return baseType;
                baseType = baseType.BaseType;
            }
        }

        /// <summary>
        /// 判断是否为匿名类型
        /// </summary>
        /// <param name="type">待判断的类型</param>
        /// <returns></returns>
        public static bool IsAnonymousType(this Type type)
        {
            System.Reflection.TypeInfo typeInfo = type.GetTypeInfo();
            return typeInfo.IsClass
                   && typeInfo.Attributes.HasFlag(TypeAttributes.NotPublic)
                   && typeInfo.Attributes.HasFlag(TypeAttributes.Sealed)
                   && typeInfo.BaseType == typeof(object);
        }
    }
}
